#ifndef VALUETYPE_H_
#define VALUETYPE_H_

#include "SemanticNode.h"

#include "../syntax_tree.h"

#include <vector>
#include <string>
#include <sstream>

extern std::string flattenTypeName(const SyntaxTreeNode &typeNode);
extern std::vector<std::string> flattenTemplateIdentifiers(const SyntaxTreeNode &templateUseNode);

class ValueType {
public:
	enum Types {
		UserDefinedTemplate,
		UserDefined,
		Int,
		Float,
		Bool,
		State,
		Time,
		Void,
		Facility,
		Storage,
		Queue,
		ADTable,
		Group,
		OutputStream
	};

	ValueType(Types type, int dimensions = 0);
	ValueType(SyntaxTreeNode *variableTypeNode, int dimensions = 0);

	ValueType(int id);
	ValueType(ValueType &copy);

	Types getType() const;
	static Types getType(std::string typeName);
	int getID() const;
	int getDimensions() const;
	std::string getTypeName() const;

	void setType(Types type, int nDimensions = 0);
	void setType(const SyntaxTreeNode *variableTypeNode, int nDimensions = 0);
	void setID(int newID);

	bool isInt() const;
	bool isFloat() const;
	bool isBool() const;
	bool isState() const;
	bool isTime() const;
	bool isVoid() const;
	bool isFacility() const;
	bool isStorage() const;
	bool isQueue() const;
	bool isADTable() const;
	bool isGroup() const;
	bool isOutputStream() const;
	bool isUserDefinedType() const;

	bool isArray() const;
	bool isConstant() const;
	bool isEvaluated() const;
	bool hasTemplate() const;

	bool operator==(const ValueType &type) const;
	bool operator!=(const ValueType &type) const;

	std::string getTypeDebugString();

protected:
	/** Value node ID. */
	int id;
	/** Dimensionality, for when dimensions vector is unknown. */
	int dimensionality;
	/** Templates. */
	std::vector<ValueType *> myTemplate;
	/** Dimensions. */
	std::vector<int> dimensions;
	/** Determines whether this value has been evaluated. */
	bool evaluated;

	void setTemplate(std::vector<std::string> names);

	void makeConstant();

private:
	/** Type of the value. */
	Types type;
	/** Type name. */
	std::string typeName;
	/** Determines whether this value is a constant. */
	bool constant;

	void setTypeName(Types type);
	bool compareTemplates(const ValueType &type) const;

	friend std::string flattenTypeName(const SyntaxTreeNode &typeNode);
};

#endif
